﻿using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using HttpApiGateway.FileUp;
using HttpApiGateway.FileUp.Interface;
using HttpApiGateway.Handler;
using HttpApiGateway.Interface;
using HttpApiGateway.Model;
using HttpService.Interface;
using RpcHelper;

namespace HttpApiGateway.Collect
{
    internal class BlockUpCollect
    {
        private static readonly ConcurrentDictionary<string, IBlockUpTask> _UpTaskList = new ConcurrentDictionary<string, IBlockUpTask>();
        private static readonly ConcurrentDictionary<string, string> _TaskDic = new ConcurrentDictionary<string, string>();
        private static IBasicHandler _upHandler;
        private static UpConfig _upConfig;
        private static Timer _Timer = null;
        public static void Init()
        {
            IHttpConfig config = RpcClient.RpcClient.Unity.Resolve<IHttpConfig>();
            config.RefreshEvent(((a, b) =>
            {
                if (b.StartsWith("UpConfig:"))
                {
                    _Refresh(a.UpConfig);
                }
            }));
            _Timer = new Timer(_Clear, null, 10000, 10000);
            _Refresh(config.UpConfig);
        }
        private static void _Clear(object state)
        {
            if (_UpTaskList.IsEmpty)
            {
                return;
            }
            string[] keys = _UpTaskList.Keys.ToArray();
            int time = HeartbeatTimeHelper.HeartbeatTime - _upConfig.BlockUpOverTime;
            keys.ForEach(a =>
            {
                if (_UpTaskList.TryGetValue(a, out IBlockUpTask task) && task.TimeOut <= time)
                {
                    Remove(a);
                }
            });
        }
        public static void SyncTask(IBlockUpTask task)
        {
            if (_TaskDic.TryGetValue(task.TaskKey, out string taskId))
            {
                if (taskId == task.TaskId)
                {
                    return;
                }
                _SetUpError(taskId, "gateway.http.up.task.tovoid");
                return;
            }
            _TaskDic.TryAdd(task.TaskKey, task.TaskId);
        }
        private static void _SetUpError(string taskId, string error)
        {
            if (_UpTaskList.TryGetValue(taskId, out IBlockUpTask task))
            {
                task.UpError(error);
            }
        }
        private static void _Refresh(UpConfig config)
        {
            _upConfig = config;
            if (config.EnableBlock)
            {
                config.BlockUpUri = config.BlockUpUri.ToLower();
            }
            if (config.EnableBlock && _upHandler == null)
            {
                _upHandler = new HttpBlockUpHandler(config.BlockUpUri, config.BlockUpUriIsRegex);
                HttpService.HttpService.AddRoute(_upHandler);
            }
            else if (!config.EnableBlock && _upHandler != null)
            {
                HttpService.HttpService.RemoveRoute(_upHandler.RequestPath, _upHandler.IsRegex);
                _upHandler = null;
            }
            else if (config.EnableBlock && _upHandler != null && config.BlockUpUri != _upHandler.RequestPath)
            {
                IBasicHandler handler = new HttpBlockUpHandler(config.BlockUpUri, config.BlockUpUriIsRegex);
                HttpService.HttpService.ReplaceRoute(_upHandler, handler);
                _upHandler = handler;
            }
        }


        internal static void Remove(string taskId)
        {
            if (!_UpTaskList.TryRemove(taskId, out IBlockUpTask task))
            {
                return;
            }
            task.Dispose();
            if (_TaskDic.TryGetValue(task.TaskKey, out string id) && id == taskId)
            {
                _TaskDic.TryRemove(task.TaskKey, out _);
            }
        }

        public static bool GetTask(string taskId, out IBlockUpTask task)
        {
            return _UpTaskList.TryGetValue(taskId, out task);
        }
        public static IBlockUpTask Add(IService service, IUpBlockFile upEvent)
        {
            IBlockUpTask task = new BlockUpTask(upEvent, service.ServiceName, _upConfig);
            if (_UpTaskList.TryAdd(task.TaskId, task))
            {
                return task;
            }
            throw new RpcHelper.ErrorException("http.gateway.block.up.task.add.fail");
        }
    }
}
